use crate::database::{AppConfig, LogEntry};
use crate::state::AppState;
use crate::validation::{Validator, ValidationRule, sanitize_string, sanitize_filename};
use crate::performance::{get_performance_monitor, PerformanceReport};
use anyhow::Result;
use chrono::Utc;
use serde::{Deserialize, Serialize};
use std::sync::Mutex;
use std::path::Path;
use std::fs;
use chrono;
use sysinfo::System;
use tauri::{AppHandle, Manager, State};
use uuid::Uuid;

#[derive(Debug, Serialize, Deserialize)]
pub struct FileItem {
    pub name: String,
    pub path: String,
    pub is_directory: bool,
    pub size: Option<u64>,
    pub modified: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct AppInfo {
    pub name: String,
    pub version: String,
    pub tauri_version: String,
    pub identifier: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct SystemInfo {
    pub platform: String,
    pub arch: String,
    pub version: String,
    pub hostname: String,
    pub uptime: u64,
    pub total_memory: u64,
    pub free_memory: u64,
    pub cpu_count: usize,
    pub load_average: Vec<f64>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct TestCommandRequest {
    pub message: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct TestCommandResponse {
    pub message: String,
    pub timestamp: String,
    pub echo: String,
}

/// 前端发送的配置结构体（不包含数据库特定字段）
#[derive(Debug, Serialize, Deserialize)]
pub struct FrontendAppConfig {
    pub theme: String,
    pub language: String,
    pub autoStart: bool,
    pub minimizeToTray: bool,
    pub notifications: bool,
    pub shortcuts: FrontendShortcuts,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct FrontendShortcuts {
    pub toggleWindow: String,
    pub newItem: String,
    pub search: String,
}

// App information commands
#[tauri::command]
pub async fn get_app_info(app: AppHandle) -> Result<AppInfo, String> {
    let package_info = app.package_info();
    
    Ok(AppInfo {
        name: package_info.name.clone(),
        version: package_info.version.to_string(),
        tauri_version: env!("CARGO_PKG_VERSION").to_string(),
        identifier: app.config().identifier.clone(),
    })
}

#[tauri::command]
pub async fn get_system_info() -> Result<SystemInfo, String> {
    let mut system = System::new_all();
    system.refresh_all();

    Ok(SystemInfo {
        platform: std::env::consts::OS.to_string(),
        arch: std::env::consts::ARCH.to_string(),
        version: System::os_version().unwrap_or_else(|| "Unknown".to_string()),
        hostname: System::host_name().unwrap_or_else(|| "Unknown".to_string()),
        uptime: System::uptime(),
        total_memory: system.total_memory(),
        free_memory: system.free_memory(),
        cpu_count: system.cpus().len(),
        load_average: vec![0.0, 0.0, 0.0], // Simplified - load_average API changed
    })
}

// Configuration commands
#[tauri::command]
pub async fn get_app_config(state: State<'_, Mutex<AppState>>) -> Result<AppConfig, String> {
    let app_state = state.lock().map_err(|e| format!("Failed to lock state: {}", e))?;
    
    match app_state.database.get_config() {
        Ok(config) => Ok(config),
        Err(e) => {
            log::warn!("Failed to get config, using default: {}", e);
            // Return default config if none exists
            let default_config = AppConfig::default();
            Ok(default_config)
        }
    }
}

#[tauri::command]
pub async fn set_app_config(
    frontendConfig: FrontendAppConfig,
    state: State<'_, Mutex<AppState>>,
) -> Result<bool, String> {
    let app_state = state.lock().map_err(|e| format!("Failed to lock state: {}", e))?;

    // Get existing config or create default
    let existing_config = app_state.database.get_config()
        .unwrap_or_else(|_| AppConfig::default());

    // Convert frontend shortcuts to database format
    let shortcuts_json = serde_json::json!({
        "toggle_window": frontendConfig.shortcuts.toggleWindow,
        "new_item": frontendConfig.shortcuts.newItem,
        "search": frontendConfig.shortcuts.search
    });

    // Create updated config with frontend values and preserve database fields
    let updated_config = AppConfig {
        id: existing_config.id,
        theme: frontendConfig.theme,
        language: frontendConfig.language,
        auto_start: frontendConfig.autoStart,
        minimize_to_tray: frontendConfig.minimizeToTray,
        notifications: frontendConfig.notifications,
        shortcuts: shortcuts_json,
        created_at: existing_config.created_at,
        updated_at: Utc::now(),
    };

    match app_state.database.save_config(&updated_config) {
        Ok(_) => {
            log::info!("Configuration updated successfully: language={}, theme={}",
                      updated_config.language, updated_config.theme);
            Ok(true)
        }
        Err(e) => {
            log::error!("Failed to save config: {}", e);
            Err(format!("Failed to save config: {}", e))
        }
    }
}

// Test commands
#[tauri::command]
pub async fn test_command(request: TestCommandRequest) -> Result<TestCommandResponse, String> {
    log::info!("Test command called with message: {}", request.message);

    Ok(TestCommandResponse {
        message: "Hello from Rust backend!".to_string(),
        timestamp: Utc::now().to_rfc3339(),
        echo: request.message,
    })
}

#[tauri::command]
pub async fn generate_test_logs(state: State<'_, Mutex<AppState>>) -> Result<String, String> {
    log::info!("Generating test logs...");

    let app_state = state.lock().map_err(|e| format!("Failed to lock state: {}", e))?;

    // 生成各种类型的测试日志并写入数据库
    let test_logs = vec![
        ("DEBUG", "System initialization check", Some("system")),
        ("INFO", "User session started", Some("auth")),
        ("WARN", "Memory usage is at 75%", Some("system")),
        ("ERROR", "Failed to connect to external service", Some("network")),
        ("INFO", "Processing user request", Some("api")),
        ("DEBUG", "Validating input parameters", Some("validation")),
        ("INFO", "Database query executed successfully", Some("database")),
        ("WARN", "Slow query detected (>1000ms)", Some("database")),
        ("DEBUG", "Cache hit ratio: 85%", Some("cache")),
        ("INFO", "Background task completed", Some("scheduler")),
        ("WARN", "Disk usage is at 90%", Some("system")),
        ("ERROR", "Network timeout occurred", Some("network")),
        ("INFO", "System health check passed", Some("health")),
        ("DEBUG", "Memory cleanup completed", Some("system")),
        ("WARN", "SSL certificate expires in 30 days", Some("security")),
        ("ERROR", "Authentication failed for user", Some("auth")),
    ];

    // 将日志写入数据库
    for (level, message, component) in test_logs {
        if let Err(e) = app_state.database.add_log(level, message, component) {
            log::error!("Failed to add log to database: {}", e);
        }

        // 同时输出到控制台
        match level {
            "DEBUG" => log::debug!("{}: {}", component.unwrap_or("app"), message),
            "INFO" => log::info!("{}: {}", component.unwrap_or("app"), message),
            "WARN" => log::warn!("{}: {}", component.unwrap_or("app"), message),
            "ERROR" => log::error!("{}: {}", component.unwrap_or("app"), message),
            _ => log::info!("{}: {}", component.unwrap_or("app"), message),
        }
    }

    log::info!("Test logs generation completed");

    Ok("Test logs generated successfully".to_string())
}

#[tauri::command]
pub async fn generate_old_test_logs(state: State<'_, Mutex<AppState>>) -> Result<String, String> {
    log::info!("Generating old test logs...");

    let app_state = state.lock().map_err(|e| format!("Failed to lock state: {}", e))?;

    // 生成不同时间的旧日志
    let now = chrono::Utc::now();
    let old_logs = vec![
        // 10天前的日志
        (now - chrono::Duration::days(10), "ERROR", "Old error: System crash 10 days ago", Some("system")),
        (now - chrono::Duration::days(10), "WARN", "Old warning: Memory leak detected 10 days ago", Some("memory")),
        (now - chrono::Duration::days(10), "INFO", "Old info: Backup completed 10 days ago", Some("backup")),

        // 15天前的日志
        (now - chrono::Duration::days(15), "ERROR", "Very old error: Database corruption 15 days ago", Some("database")),
        (now - chrono::Duration::days(15), "WARN", "Very old warning: Disk full 15 days ago", Some("storage")),

        // 30天前的日志
        (now - chrono::Duration::days(30), "ERROR", "Ancient error: Network failure 30 days ago", Some("network")),
        (now - chrono::Duration::days(30), "INFO", "Ancient info: System update 30 days ago", Some("update")),

        // 5天前的日志（应该不会被清理）
        (now - chrono::Duration::days(5), "INFO", "Recent info: User activity 5 days ago", Some("user")),
        (now - chrono::Duration::days(5), "WARN", "Recent warning: High CPU usage 5 days ago", Some("cpu")),
    ];

    // 将旧日志写入数据库
    for (timestamp, level, message, component) in old_logs {
        let timestamp_str = timestamp.to_rfc3339();
        if let Err(e) = app_state.database.add_log_with_timestamp(level, message, component, &timestamp_str) {
            log::error!("Failed to add old log to database: {}", e);
        }
    }

    log::info!("Old test logs generation completed");

    Ok("Old test logs generated successfully".to_string())
}

// Logging commands
#[tauri::command]
pub async fn get_logs(
    limit: Option<usize>,
    level_filter: Option<String>,
    state: State<'_, Mutex<AppState>>,
) -> Result<Vec<LogEntry>, String> {
    let app_state = state.lock().map_err(|e| format!("Failed to lock state: {}", e))?;
    
    match app_state.database.get_logs(limit.map(|l| l as i32), level_filter.as_deref()) {
        Ok(logs) => Ok(logs),
        Err(e) => Err(format!("Failed to get logs: {}", e)),
    }
}

#[tauri::command]
pub async fn clear_logs(
    days: Option<i64>,
    state: State<'_, Mutex<AppState>>,
) -> Result<usize, String> {
    let app_state = state.lock().map_err(|e| format!("Failed to lock state: {}", e))?;

    let days_before = days.unwrap_or(7); // 默认清理7天前的日志
    match app_state.database.clear_logs_before_days(days_before as i32) {
        Ok(deleted_count) => {
            log::info!("Cleared {} log entries older than {} days", deleted_count, days_before);
            Ok(deleted_count)
        }
        Err(e) => {
            log::error!("Failed to clear logs: {}", e);
            Err(format!("Failed to clear logs: {}", e))
        }
    }
}

#[tauri::command]
pub async fn get_log_stats(state: State<'_, Mutex<AppState>>) -> Result<serde_json::Value, String> {
    let app_state = state.lock().map_err(|e| format!("Failed to lock state: {}", e))?;
    
    match app_state.database.get_log_stats() {
        Ok(stats) => Ok(stats),
        Err(e) => Err(format!("Failed to get log stats: {}", e)),
    }
}

// File system commands
#[tauri::command]
pub async fn read_text_file(path: String) -> Result<String, String> {
    // 首先检查文件是否存在
    if !Path::new(&path).exists() {
        return Err("File does not exist".to_string());
    }

    // 检查是否是文件（不是目录）
    if !Path::new(&path).is_file() {
        return Err("Path is not a file".to_string());
    }

    // 检查文件扩展名，只允许文本文件
    let allowed_extensions = [
        "txt", "md", "json", "js", "ts", "tsx", "jsx", "css", "html", "htm",
        "xml", "yaml", "yml", "toml", "ini", "cfg", "conf", "log", "csv",
        "rs", "py", "java", "c", "cpp", "h", "hpp", "go", "php", "rb",
        "sh", "bat", "ps1", "sql", "gitignore", "dockerfile", "makefile"
    ];

    let extension = Path::new(&path)
        .extension()
        .and_then(|ext| ext.to_str())
        .unwrap_or("")
        .to_lowercase();

    // 如果有扩展名但不在允许列表中，检查文件大小
    if !extension.is_empty() && !allowed_extensions.contains(&extension.as_str()) {
        return Err(format!("File type '.{}' is not supported for text editing", extension));
    }

    // 检查文件大小，避免读取过大的文件
    if let Ok(metadata) = std::fs::metadata(&path) {
        const MAX_FILE_SIZE: u64 = 10 * 1024 * 1024; // 10MB
        if metadata.len() > MAX_FILE_SIZE {
            return Err("File is too large to open (max 10MB)".to_string());
        }
    }

    // 尝试读取文件
    match std::fs::read_to_string(&path) {
        Ok(content) => {
            log::info!("Successfully read file: {} ({} bytes)", path, content.len());
            log::debug!("File content preview: {}...",
                content.chars().take(100).collect::<String>().replace('\n', "\\n"));
            Ok(content)
        }
        Err(e) => {
            log::error!("Failed to read file {}: {}", path, e);
            // 提供更友好的错误信息
            if e.kind() == std::io::ErrorKind::InvalidData {
                log::warn!("File {} contains invalid UTF-8 data", path);
                Err("File contains invalid UTF-8 data. This file may be binary or use a different encoding.".to_string())
            } else {
                Err(format!("Failed to read file: {}", e))
            }
        }
    }
}

#[tauri::command]
pub async fn write_text_file(path: String, content: String) -> Result<bool, String> {
    // Validate input
    let validator = Validator::new()
        .add_rule("path", ValidationRule::required())
        .add_rule("content", ValidationRule::required());

    validator.validate_string("path", Some(&path))
        .map_err(|e| format!("Path validation failed: {}", e))?;

    validator.validate_string("content", Some(&content))
        .map_err(|e| format!("Content validation failed: {}", e))?;

    // Sanitize path to prevent directory traversal
    let sanitized_path = sanitize_filename(&path);
    if sanitized_path != path {
        return Err("Invalid characters in file path".to_string());
    }

    // Sanitize content
    let sanitized_content = sanitize_string(&content);

    match std::fs::write(&path, &sanitized_content) {
        Ok(_) => {
            log::info!("Successfully wrote file: {} ({} bytes)", path, sanitized_content.len());
            log::debug!("File write operation completed for: {}", path);
            Ok(true)
        }
        Err(e) => {
            log::error!("Failed to write file {}: {}", path, e);
            log::warn!("Write operation failed, check file permissions for: {}", path);
            Err(format!("Failed to write file: {}", e))
        }
    }
}

#[tauri::command]
pub async fn file_exists(path: String) -> Result<bool, String> {
    Ok(std::path::Path::new(&path).exists())
}

#[tauri::command]
pub async fn is_text_file(path: String) -> Result<bool, String> {
    let file_path = Path::new(&path);

    if !file_path.exists() || !file_path.is_file() {
        return Ok(false);
    }

    // 检查文件扩展名
    let text_extensions = [
        "txt", "md", "json", "js", "ts", "tsx", "jsx", "css", "html", "htm",
        "xml", "yaml", "yml", "toml", "ini", "cfg", "conf", "log", "csv",
        "rs", "py", "java", "c", "cpp", "h", "hpp", "go", "php", "rb",
        "sh", "bat", "ps1", "sql", "gitignore", "dockerfile", "makefile"
    ];

    let extension = file_path
        .extension()
        .and_then(|ext| ext.to_str())
        .unwrap_or("")
        .to_lowercase();

    // 如果没有扩展名，尝试读取前几个字节来判断
    if extension.is_empty() {
        match std::fs::read(&path) {
            Ok(bytes) => {
                if bytes.is_empty() {
                    return Ok(true); // 空文件视为文本文件
                }

                // 检查前1024字节是否包含null字节（二进制文件的特征）
                let sample_size = std::cmp::min(1024, bytes.len());
                let sample = &bytes[..sample_size];

                // 如果包含null字节，很可能是二进制文件
                if sample.contains(&0) {
                    return Ok(false);
                }

                // 尝试将样本解析为UTF-8
                Ok(std::str::from_utf8(sample).is_ok())
            }
            Err(_) => Ok(false),
        }
    } else {
        Ok(text_extensions.contains(&extension.as_str()))
    }
}

#[tauri::command]
pub async fn create_directory(path: String) -> Result<bool, String> {
    match std::fs::create_dir_all(&path) {
        Ok(_) => {
            log::info!("Successfully created directory: {}", path);
            log::debug!("Directory creation completed: {}", path);
            Ok(true)
        }
        Err(e) => {
            log::error!("Failed to create directory {}: {}", path, e);
            log::warn!("Directory creation failed, check permissions: {}", path);
            Err(format!("Failed to create directory: {}", e))
        }
    }
}

#[tauri::command]
pub async fn read_directory(path: String) -> Result<Vec<FileItem>, String> {
    let dir_path = Path::new(&path);

    if !dir_path.exists() {
        return Err("Directory does not exist".to_string());
    }

    if !dir_path.is_dir() {
        return Err("Path is not a directory".to_string());
    }

    log::info!("Reading directory: {}", path);

    match fs::read_dir(dir_path) {
        Ok(entries) => {
            let mut files = Vec::new();
            let mut file_count = 0;
            let mut dir_count = 0;

            for entry in entries {
                match entry {
                    Ok(entry) => {
                        let path = entry.path();
                        let name = entry.file_name().to_string_lossy().to_string();
                        let is_directory = path.is_dir();

                        let (size, modified) = if let Ok(metadata) = entry.metadata() {
                            let size = if is_directory { None } else { Some(metadata.len()) };
                            let modified = metadata.modified()
                                .ok()
                                .and_then(|time| time.duration_since(std::time::UNIX_EPOCH).ok())
                                .map(|duration| {
                                    chrono::DateTime::from_timestamp(duration.as_secs() as i64, 0)
                                        .map(|dt| dt.to_rfc3339())
                                        .unwrap_or_else(|| "Unknown".to_string())
                                });
                            (size, modified)
                        } else {
                            (None, None)
                        };

                        files.push(FileItem {
                            name,
                            path: path.to_string_lossy().to_string(),
                            is_directory,
                            size,
                            modified,
                        });

                        if is_directory {
                            dir_count += 1;
                        } else {
                            file_count += 1;
                        }
                    }
                    Err(e) => {
                        log::warn!("Failed to read directory entry: {}", e);
                    }
                }
            }

            // 排序：目录在前，然后按名称排序
            files.sort_by(|a, b| {
                match (a.is_directory, b.is_directory) {
                    (true, false) => std::cmp::Ordering::Less,
                    (false, true) => std::cmp::Ordering::Greater,
                    _ => a.name.to_lowercase().cmp(&b.name.to_lowercase()),
                }
            });

            log::info!("Directory read completed: {} files, {} directories", file_count, dir_count);
            log::debug!("Total items in directory {}: {}", path, files.len());

            Ok(files)
        }
        Err(e) => {
            log::error!("Failed to read directory {}: {}", path, e);
            Err(format!("Failed to read directory: {}", e))
        }
    }
}

#[tauri::command]
pub async fn get_current_directory() -> Result<String, String> {
    match std::env::current_dir() {
        Ok(path) => Ok(path.to_string_lossy().to_string()),
        Err(e) => {
            log::error!("Failed to get current directory: {}", e);
            Err(format!("Failed to get current directory: {}", e))
        }
    }
}

#[tauri::command]
pub async fn get_home_directory() -> Result<String, String> {
    match dirs::home_dir() {
        Some(path) => Ok(path.to_string_lossy().to_string()),
        None => Err("Failed to get home directory".to_string()),
    }
}

// Window management commands
#[tauri::command]
pub async fn toggle_window_visibility(app: AppHandle) -> Result<bool, String> {
    if let Some(window) = app.get_webview_window("main") {
        match window.is_visible() {
            Ok(true) => {
                window.hide().map_err(|e| format!("Failed to hide window: {}", e))?;
                Ok(false)
            }
            Ok(false) => {
                window.show().map_err(|e| format!("Failed to show window: {}", e))?;
                window.set_focus().map_err(|e| format!("Failed to focus window: {}", e))?;
                Ok(true)
            }
            Err(e) => Err(format!("Failed to get window visibility: {}", e)),
        }
    } else {
        Err("Main window not found".to_string())
    }
}

#[tauri::command]
pub async fn center_window(app: AppHandle) -> Result<bool, String> {
    if let Some(window) = app.get_webview_window("main") {
        window.center().map_err(|e| format!("Failed to center window: {}", e))?;
        Ok(true)
    } else {
        Err("Main window not found".to_string())
    }
}

// Utility commands
#[tauri::command]
pub async fn generate_uuid() -> Result<String, String> {
    Ok(Uuid::new_v4().to_string())
}

#[tauri::command]
pub async fn get_current_timestamp() -> Result<String, String> {
    Ok(Utc::now().to_rfc3339())
}

// Process management commands
#[tauri::command]
pub async fn get_process_info() -> Result<serde_json::Value, String> {
    let mut system = System::new_all();
    system.refresh_all();

    let current_pid = std::process::id();
    
    if let Some(process) = system.process(sysinfo::Pid::from(current_pid as usize)) {
        let info = serde_json::json!({
            "pid": current_pid,
            "name": process.name(),
            "cpu_usage": process.cpu_usage(),
            "memory": process.memory(),
            "virtual_memory": process.virtual_memory(),
            "start_time": process.start_time(),
            "run_time": process.run_time(),
        });
        
        Ok(info)
    } else {
        Err("Failed to get current process info".to_string())
    }
}

// Application lifecycle commands
#[tauri::command]
pub async fn quit_app(app: AppHandle) -> Result<(), String> {
    log::info!("Application quit requested");
    app.exit(0);
    Ok(())
}

#[tauri::command]
pub async fn restart_app(app: AppHandle) -> Result<(), String> {
    log::info!("Application restart requested");
    app.restart();
    // Note: This line is unreachable as restart() doesn't return
    #[allow(unreachable_code)]
    Ok(())
}

// 性能监控命令
#[tauri::command]
pub async fn get_performance_metrics() -> Result<crate::performance::PerformanceMetrics, String> {
    let monitor = get_performance_monitor();
    Ok(monitor.collect_metrics())
}

#[tauri::command]
pub async fn get_performance_report() -> Result<PerformanceReport, String> {
    let monitor = get_performance_monitor();
    Ok(monitor.generate_report())
}

#[tauri::command]
pub async fn start_performance_event(name: String, metadata: std::collections::HashMap<String, serde_json::Value>) -> Result<String, String> {
    let monitor = get_performance_monitor();
    Ok(monitor.start_event(&name, metadata))
}

#[tauri::command]
pub async fn end_performance_event(event_id: String) -> Result<Option<crate::performance::PerformanceEvent>, String> {
    let monitor = get_performance_monitor();
    Ok(monitor.end_event(&event_id))
}

#[tauri::command]
pub async fn set_custom_metric(name: String, value: f64) -> Result<(), String> {
    let monitor = get_performance_monitor();
    monitor.set_custom_metric(&name, value);
    Ok(())
}

#[tauri::command]
pub async fn increment_custom_metric(name: String, value: f64) -> Result<(), String> {
    let monitor = get_performance_monitor();
    monitor.increment_custom_metric(&name, value);
    Ok(())
}

#[tauri::command]
pub async fn get_performance_history(limit: Option<usize>) -> Result<Vec<crate::performance::PerformanceMetrics>, String> {
    let monitor = get_performance_monitor();
    Ok(monitor.get_metrics_history(limit))
}

#[tauri::command]
pub async fn clear_performance_data() -> Result<(), String> {
    let monitor = get_performance_monitor();
    monitor.cleanup();
    Ok(())
}
